/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.common.base.service.impl.move;

import com.google.common.base.Strings;
import com.je.common.base.DynaBean;
import com.je.common.base.constants.tree.NodeType;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.MetaService;
import com.je.common.base.service.MoveService;
import com.je.common.base.service.rpc.BeanService;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public abstract class AbstractMoveService implements MoveService {

    private static final Logger logger = LoggerFactory.getLogger(AbstractMoveService.class);
    @Autowired
    public MetaService metaService;
    @Autowired
    public CommonService commonService;
    @Autowired
    private BeanService beanService;

    /**
     * 在上面
     */
    public static final String ABOVE = "above";
    /**
     * 在下面
     */
    public static final String BELOW = "below";
    /**
     * 在里面
     */
    public static final String INSIDE = "inside";

    /*
        1.查出整个树形表数据，按照树形排序字段排序
        2.取出要移动的节点信息
        3.放到要放的目标节点位置，生成新的list数据
        4.重新遍历整个树，找出排序不正确的节点，生成更新的sql，进行重排
        **注意需要更新的字段
        SY_PARENT、SY_PATH、SY_TREEORDERINDEX、SY_LAYER、SY_ORDERINDEX
     */
    @Override
    public void move(String tableCode, String id, String toId, DynaBean fromBean, DynaBean toResource) {
        JSONTreeNode template = beanService.getTreeTemplate(tableCode);
        //TODO 单根树、多根树 条件
        List<DynaBean> oldDynaBeanList = metaService.select(tableCode, ConditionsWrapper.builder().apply("order by SY_TREEORDERINDEX asc , SY_ORDERINDEX asc"));
        List<DynaBean> newDynaBeanList = new ArrayList<>(oldDynaBeanList);
        newDynaBeanList.remove(fromBean);
        int index = 0;
        for (int i = 0; i < newDynaBeanList.size(); i++) {
            if (newDynaBeanList.get(i).getPkValue().equals(toId)) {
                index = i;
                break;
            }
        }
        //根据具体位置进行替换塞值
        newDynaBeanList.add(index, fromBean);


        //获取树形表数据
        List<Map<String, Object>> oldMapList = new ArrayList<>();
        for (DynaBean dynaBean : oldDynaBeanList) {
            oldMapList.add(dynaBean.getValues());
        }
        List<JSONTreeNode> oldJsonTreeNodeList = commonService.buildJsonTreeNodeList(template, oldMapList, null, null, true);

        //获取树形表数据
        List<Map<String, Object>> newMapList = new ArrayList<>();
        for (DynaBean dynaBean : newDynaBeanList) {
            newMapList.add(dynaBean.getValues());
        }
        List<JSONTreeNode> newJsonTreeNodeList = commonService.buildJsonTreeNodeList(template, newMapList, null, null, true);

        //重排树
        for (int i = 0; i < newJsonTreeNodeList.size(); i++) {
            JSONTreeNode jsonTreeNode = newJsonTreeNodeList.get(i);
            if (jsonTreeNode.getChildren() == null) {
                return;
            }
            jsonTreeNode.getId();
        }


    }


    /**
     * 确认平级
     *
     * @param fromBean
     * @param toResource
     * @return
     */
    public Boolean sameLevel(DynaBean fromBean, DynaBean toResource) {
        String fromParentId = fromBean.getStr("SY_PARENT");
        String toParentId = toResource.getStr("SY_PARENT");
        if (fromParentId.equals(toParentId)) {
            return true;
        }
        return false;
    }

    public String getUpdateLevelAndChildSql(String tableCode, DynaBean resourceOne, DynaBean resourceTwo, String place) {
        //发起层所有
        List<DynaBean> fromList = metaService.select(tableCode, ConditionsWrapper.builder().eq("SY_PARENT", resourceOne.getStr("SY_PARENT")).apply("order by SY_TREEORDERINDEX asc , SY_ORDERINDEX asc"));
        List<DynaBean> fromDynaBeanList = new ArrayList<>(fromList);
        //找到要移动的参数先移除他
        int fromIndex = -1;
        for (int i = 0; i < fromDynaBeanList.size(); i++) {
            if (fromDynaBeanList.get(i).getPkValue().equals(resourceOne.getPkValue())) {
                fromIndex = i;
            }
        }
        if (fromIndex != -1) {
            fromDynaBeanList.remove(fromIndex);
        }
        int index = 0;
        for (int i = 0; i < fromDynaBeanList.size(); i++) {
            if (fromDynaBeanList.get(i).getPkValue().equals(resourceTwo.getPkValue())) {
                index = i;
                break;
            }
        }
        //根据具体位置进行替换塞值(在下面 索引加一，在上面 索引位置)
        int resultIndex = -1;
        if (BELOW.equals(place)) {
            resultIndex = index + 1;
            fromDynaBeanList.add(resultIndex, resourceOne);

        } else if (ABOVE.equals(place)) {
            resultIndex = index;
            fromDynaBeanList.add(resultIndex, resourceOne);
        }

        StringBuffer updateSql = new StringBuffer();
        //SY_PARENT、SY_PATH、SY_LAYER、没有变 只重新排序 SY_ORDERINDEX、SY_TREEORDERINDEX、
        for (int i = 0; i < fromDynaBeanList.size(); i++) {
            DynaBean oldDynaBean = copyBean(fromDynaBeanList.get(i));
            String treeIndex = "";
            if (oldDynaBean.getStr("SY_TREEORDERINDEX").length() <= 6) {
                treeIndex = "000001" + String.format("%06d", i + 1);
            } else {
                treeIndex = oldDynaBean.getStr("SY_TREEORDERINDEX").substring(0, oldDynaBean.getStr("SY_TREEORDERINDEX").length() - 6) + String.format("%06d", i + 1);
            }
            fromDynaBeanList.get(i).set("SY_ORDERINDEX", i + 1);
            fromDynaBeanList.get(i).set("SY_TREEORDERINDEX", treeIndex);

            String sql = "";
            sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_ORDERINDEX = '%s' where %s = '%s';",
                    fromDynaBeanList.get(i).getTableCode(), treeIndex, i + 1, fromDynaBeanList.get(i).getPkCode(), fromDynaBeanList.get(i).getPkValue());

            String fromChildSql = getUpdateChildTreeOrderIndexSql(fromDynaBeanList.get(i), oldDynaBean, true, resourceOne);
            if (!Strings.isNullOrEmpty(sql)) {
                updateSql.append(sql);
            }
            if (!Strings.isNullOrEmpty(fromChildSql)) {
                updateSql.append(fromChildSql);
            }
        }
        updateSqlSer(updateSql.toString());

        return updateSql.toString();
    }

    public String getFromAndChildUpdateSql(String tableCode, DynaBean resourceOne, List<DynaBean> fromDynaBeanList) {
        //发起层所有
        List<DynaBean> fromList = metaService.select(tableCode, ConditionsWrapper.builder().eq("SY_PARENT", resourceOne.getStr("SY_PARENT")).apply("order by SY_TREEORDERINDEX asc , SY_ORDERINDEX asc"));
        fromDynaBeanList = new ArrayList<>(fromList);
        int fromIndex = -1;
        for (int i = 0; i < fromDynaBeanList.size(); i++) {
            if (fromDynaBeanList.get(i).getPkValue().equals(resourceOne.getPkValue())) {
                fromIndex = i;
            }
        }
        if (fromIndex != -1) {
            fromDynaBeanList.remove(fromIndex);
        }

        StringBuffer updateSql = new StringBuffer();
        //SY_PARENT、SY_PATH、SY_LAYER、没有变 只重新排序 SY_ORDERINDEX、SY_TREEORDERINDEX、
        for (int i = 0; i < fromDynaBeanList.size(); i++) {
            DynaBean oldDynaBean = copyBean(fromDynaBeanList.get(i));
            String treeIndex = oldDynaBean.getStr("SY_TREEORDERINDEX").substring(0, oldDynaBean.getStr("SY_TREEORDERINDEX").length() - 6) + String.format("%06d", i + 1);
            fromDynaBeanList.get(i).set("SY_ORDERINDEX", i + 1);
            fromDynaBeanList.get(i).set("SY_TREEORDERINDEX", treeIndex);

            String sql = "";
            sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_ORDERINDEX = '%s' where %s = '%s';",
                    fromDynaBeanList.get(i).getTableCode(), treeIndex, i + 1, fromDynaBeanList.get(i).getPkCode(), fromDynaBeanList.get(i).getPkValue());

            String fromChildSql = getUpdateChildTreeOrderIndexSql(fromDynaBeanList.get(i), oldDynaBean, true, resourceOne);
            if (!Strings.isNullOrEmpty(sql)) {
                updateSql.append(sql);
            }
            if (!Strings.isNullOrEmpty(fromChildSql)) {
                updateSql.append(fromChildSql);
            }

        }
        if (fromList.size() == 1) {
            String sql = String.format("UPDATE %s set SY_NODETYPE = '%s' where %s = '%s';",
                    tableCode, NodeType.LEAF, fromList.get(0).getPkCode(), resourceOne.getStr("SY_PARENT"));
            updateSql.append(sql);
        }
        updateSqlSer(updateSql.toString());
        return updateSql.toString();
    }

    public String getUpdateSql(String tableCode, DynaBean resourceOne, DynaBean resourceTwo, String place) {
        //发起层最新的结果
        List<DynaBean> fromDynaBeanList = null;
        //获取发起层和子层修改的sql
        getFromAndChildUpdateSql(tableCode, resourceOne, fromDynaBeanList);

        resourceOne = metaService.selectOne(tableCode, ConditionsWrapper.builder().eq(resourceOne.getPkCode(), resourceOne.getPkValue()));
        resourceTwo = metaService.selectOne(tableCode, ConditionsWrapper.builder().eq(resourceTwo.getPkCode(), resourceTwo.getPkValue()));

        //目标层所有
        List<DynaBean> toList;
        if (INSIDE.equals(place)) {
            toList = metaService.select(tableCode, ConditionsWrapper.builder()
                    .eq("SY_PARENT", resourceTwo.getPkValue())
                    .apply("order by SY_TREEORDERINDEX asc , SY_ORDERINDEX asc"));
        } else {
            toList = metaService.select(tableCode, ConditionsWrapper.builder()
                    .eq("SY_PARENT", resourceTwo.getStr("SY_PARENT"))
                    .ne(resourceOne.getPkCode(), resourceOne.getPkValue())
                    .apply("order by SY_TREEORDERINDEX asc , SY_ORDERINDEX asc"));
        }
        List<DynaBean> toDynaBeanList = new ArrayList<>(toList);
        int index = 0;
        for (int i = 0; i < toDynaBeanList.size(); i++) {
            if (toDynaBeanList.get(i).getPkValue().equals(resourceTwo.getPkValue())) {
                index = i;
                break;
            }
        }
        //根据具体位置进行替换塞值(在下面 索引加一，在上面 索引位置，在里边 放到最后一个)
        int resultIndex = -1;
        if (BELOW.equals(place)) {
            resultIndex = index + 1;
            toDynaBeanList.add(resultIndex, resourceOne);

        } else if (ABOVE.equals(place)) {
            resultIndex = index;
            toDynaBeanList.add(resultIndex, resourceOne);
        } else if (INSIDE.equals(place)) {
            resultIndex = toDynaBeanList.size();
            toDynaBeanList.add(resultIndex, resourceOne);

        }
        //目标节点 SY_PARENT、SY_PATH、SY_LAYER、有变 （老表更新 SY_PARENTPATH）全部重新排序 SY_ORDERINDEX、SY_TREEORDERINDEX、
        StringBuffer updateSql = new StringBuffer();
        for (int i = 0; i < toDynaBeanList.size(); i++) {
            DynaBean oldDynaBean = copyBean(toDynaBeanList.get(i));

            String sql = "";
            if (INSIDE.equals(place)) {
                String treeIndex = resourceTwo.getStr("SY_TREEORDERINDEX") + String.format("%06d", i + 1);
                int layer = treeIndex.length() / 6 - 1;
                String path = resourceTwo.getStr("SY_PATH") + String.format("/%s", toDynaBeanList.get(i).getPkValue());
                String parentPath = resourceTwo.getStr("SY_PATH");
                toDynaBeanList.get(i).set("SY_NODETYPE", NodeType.LEAF);
                toDynaBeanList.get(i).set("SY_ORDERINDEX", i + 1);
                toDynaBeanList.get(i).set("SY_TREEORDERINDEX", treeIndex);
                if (i == (toDynaBeanList.size() - 1)) {
                    toDynaBeanList.get(i).set("SY_LAYER", layer);
                    toDynaBeanList.get(i).set("SY_PARENT", resourceTwo.getPkValue());
                    toDynaBeanList.get(i).set("SY_PATH", path);
                    String syParentpath = resourceTwo.getStr("SY_PARENTPATH");
                    if (syParentpath != null) {
                        sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_ORDERINDEX = '%s',SY_PARENT='%s',SY_PATH='%s',SY_LAYER='%s' ,SY_PARENTPATH='%s' where %s = '%s';",
                                tableCode, treeIndex, i + 1, resourceTwo.getPkValue(), path,
                                layer, parentPath, toDynaBeanList.get(i).getPkCode(), toDynaBeanList.get(i).getPkValue());
                    } else {
                        sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_ORDERINDEX = '%s',SY_PARENT='%s',SY_PATH='%s',SY_LAYER='%s' where %s = '%s';",
                                tableCode, treeIndex, i + 1, resourceTwo.getPkValue(), path,
                                layer, toDynaBeanList.get(i).getPkCode(), toDynaBeanList.get(i).getPkValue());
                    }
                } else {
                    sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_ORDERINDEX = '%s' where %s = '%s';",
                            tableCode, treeIndex, i + 1, toDynaBeanList.get(i).getPkCode(), toDynaBeanList.get(i).getPkValue());
                }
                if (!Strings.isNullOrEmpty(sql)) {
                    updateSql.append(sql);
                }
                if (resultIndex == 0) {
                    sql = String.format("UPDATE %s set SY_NODETYPE = '%s' where %s = '%s';",
                            tableCode, NodeType.GENERAL, toDynaBeanList.get(i).getPkCode(), resourceTwo.getPkValue());
                    updateSql.append(sql);
                }
            } else {
                String treeIndex = resourceTwo.getStr("SY_TREEORDERINDEX").substring(0, resourceTwo.getStr("SY_TREEORDERINDEX").length() - 6) + String.format("%06d", i + 1);
                int layer = treeIndex.length() / 6 - 1;
                String path = resourceTwo.getStr("SY_PATH").substring(0, resourceTwo.getStr("SY_PATH").lastIndexOf("/")) + String.format("/%s", toDynaBeanList.get(i).getPkValue());

                toDynaBeanList.get(i).set("SY_NODETYPE", resourceTwo.getStr("SY_NODETYPE"));
                toDynaBeanList.get(i).set("SY_ORDERINDEX", i + 1);
                toDynaBeanList.get(i).set("SY_TREEORDERINDEX", treeIndex);
                if (i == resultIndex) {
                    toDynaBeanList.get(i).set("SY_LAYER", layer);
                    toDynaBeanList.get(i).set("SY_PARENT", resourceTwo.getStr("SY_PARENT"));
                    toDynaBeanList.get(i).set("SY_PATH", path);

                    String parentPath = resourceTwo.getStr("SY_PARENTPATH");
                    if (parentPath != null) {
                        sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_ORDERINDEX = '%s',SY_PARENT='%s',SY_PATH='%s',SY_LAYER='%s' ,SY_PARENTPATH='%s' where %s = '%s';",
                                tableCode, treeIndex, i + 1, resourceTwo.getStr("SY_PARENT"), path,
                                layer, parentPath, toDynaBeanList.get(i).getPkCode(), toDynaBeanList.get(i).getPkValue());
                    } else {
                        sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_ORDERINDEX = '%s',SY_PARENT='%s',SY_PATH='%s',SY_LAYER='%s' where %s = '%s';",
                                tableCode, treeIndex, i + 1, resourceTwo.getStr("SY_PARENT"), path,
                                layer, toDynaBeanList.get(i).getPkCode(), toDynaBeanList.get(i).getPkValue());
                    }
                } else {
                    sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_ORDERINDEX = '%s' where %s = '%s';",
                            tableCode, treeIndex, i + 1, toDynaBeanList.get(i).getPkCode(), toDynaBeanList.get(i).getPkValue());
                }
                if (!Strings.isNullOrEmpty(sql)) {
                    updateSql.append(sql);
                }
            }
            String fromChildSql = getUpdateChildTreeOrderIndexSql(toDynaBeanList.get(i), oldDynaBean, true, resourceOne);

            if (!Strings.isNullOrEmpty(fromChildSql)) {
                updateSql.append(fromChildSql);
            }
        }
        updateSqlSer(updateSql.toString());
        return updateSql.toString();
    }

    public String getUpdateChildTreeOrderIndexSql(DynaBean dynaBean, DynaBean oldBean, Boolean modifyParentInfo, DynaBean resourceOne) {
        StringBuffer updateSql = new StringBuffer();
        List<DynaBean> childList = null;
        if (dynaBean.getPkValue().equals(resourceOne.getPkValue())) {
            childList = metaService.select(dynaBean.getTableCode(), ConditionsWrapper.builder().like("SY_PATH", dynaBean.getPkValue())
                    .ne(dynaBean.getPkCode(), dynaBean.getPkValue()));
        } else {
            childList = metaService.select(dynaBean.getTableCode(), ConditionsWrapper.builder().like("SY_PATH", dynaBean.getPkValue())
                    .ne(dynaBean.getPkCode(), dynaBean.getPkValue())
                    .notLike("SY_PATH", resourceOne.getPkValue()));
        }
        if (childList != null && childList.size() > 0) {
            String sql = String.format("UPDATE %s set SY_NODETYPE = '%s' where %s = '%s';",
                    dynaBean.getTableCode(), NodeType.GENERAL, dynaBean.getPkCode(), dynaBean.getPkValue());
            updateSql.append(sql);
        } else {
            String sql = String.format("UPDATE %s set SY_NODETYPE = '%s' where %s = '%s';",
                    dynaBean.getTableCode(), NodeType.LEAF, dynaBean.getPkCode(), dynaBean.getPkValue());
            updateSql.append(sql);
        }
        for (DynaBean child : childList) {
            String sql = "";
            String treeIndexStr = child.getStr("SY_TREEORDERINDEX").replaceFirst(oldBean.getStr("SY_TREEORDERINDEX"), dynaBean.getStr("SY_TREEORDERINDEX"));
            int layer = treeIndexStr.length() / 6 - 1;
            if (modifyParentInfo) {
                String path = child.getStr("SY_PATH").replace(oldBean.getStr("SY_PATH"), dynaBean.getStr("SY_PATH"));
                if (!Strings.isNullOrEmpty(child.getStr("SY_PARENTPATH"))) {
                    String parentPath = child.getStr("SY_PARENTPATH").replace(oldBean.getStr("SY_PATH"), dynaBean.getStr("SY_PATH"));
                    sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_PATH='%s',SY_LAYER='%s',SY_PARENTPATH ='%s' where %s = '%s';",
                            child.getTableCode(), treeIndexStr, path, layer, parentPath, child.getPkCode(), child.getPkValue());

                } else {
                    sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s',SY_PATH='%s',SY_LAYER='%s' where %s = '%s';",
                            child.getTableCode(), treeIndexStr, path, layer, child.getPkCode(), child.getPkValue());

                }
            } else {
                sql = String.format("UPDATE %s set SY_TREEORDERINDEX = '%s' where %s = '%s';",
                        child.getTableCode(), treeIndexStr, child.getPkCode(), child.getPkValue());
            }
            updateSql.append(sql);
        }
        return updateSql.toString();
    }

    public void updateSqlSer(String sqls) {
        Date startTime = new Date();

        int taskSize = 5;
        // 创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(taskSize);

        // 创建多个任务
        List<String> list = Arrays.asList(sqls.split(";"));
        int perSize = 0;
        if (list.size() % taskSize == 0) {
            perSize = list.size() / taskSize;
        } else {
            perSize = (list.size() / taskSize) + 1;
        }
        for (int i = 0; i < taskSize; i++) {
            if (i * perSize > list.size()) {
                return;
            }
            List<String> sqlList = list.subList(i * perSize, Math.min(((i + 1) * perSize), list.size()));
            if (sqlList.size() == 0) {
                return;
            }

            executorService.submit(() -> {
                for (String sql : sqlList) {
                    if (!Strings.isNullOrEmpty(sql) && !sql.equals(";")) {
                        metaService.executeSql(sql);
                    }
                }
            });
        }
        // 关闭线程池
        executorService.shutdown();
        //等待所有任务都执行结束
        while (true) {
            //所有的子线程都结束了
            if (executorService.isTerminated()) {
                Date endTime = new Date();
                logger.info("---- 主程序结束运行 ----，程序运行耗时【" + (endTime.getTime() - startTime.getTime()) + "毫秒】");
                break;
            }
        }
    }

    public DynaBean copyBean(DynaBean dynaBean) {
        DynaBean oldBean = new DynaBean();
        oldBean.setStr("SY_TREEORDERINDEX", dynaBean.getStr("SY_TREEORDERINDEX"));
        oldBean.setStr("SY_PARENT", dynaBean.getStr("SY_PARENT"));
        oldBean.setStr("SY_PATH", dynaBean.getStr("SY_PATH"));
        oldBean.setStr("SY_ORDERINDEX", dynaBean.getStr("SY_ORDERINDEX"));
        return oldBean;
    }

}
